﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Kitware.VTK;
using System.Drawing;

using System.ComponentModel;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

using System.IO;

namespace HAVTKPack
{
   public class Scene
   {

       #region 控件属性 包括：Control控件，vtkRenderWindow，vtkRenderer，Interractor，vtkCamera等。

       ////基类事件关系
       //[field: NonSerialized]
       //public event NodeEventA NodeAdded;
       //[field: NonSerialized]
       //public event NodeEventR NodeRemoved;


    

       [NonSerialized]
       protected vtkRenderWindow m_vtkRenderWindow;
       public vtkRenderWindow VtkRenderWindow
       {
           get { return m_vtkRenderWindow; }
       }

       [NonSerialized]
       protected vtkRenderer m_vtkRenderer;
       public vtkRenderer VtkRenderer
       {
           get { return m_vtkRenderer; }
           //set { m_vtkRenderer = value; }
       }

       [NonSerialized]
       protected vtkRenderWindowInteractor m_vtkInteractor;
       public  vtkRenderWindowInteractor VtkInteractor
       {
           get { return m_vtkInteractor; }
           //set { m_vtkInteractor = value; }
       }
     
       [NonSerialized]
       protected WorldCoordinateWidget worldCoordinata;


       [NonSerialized]
       protected RenderWindowControl m_vtkControl;

       public RenderWindowControl VtkControl
       {
           get { return m_vtkControl; }
           set { m_vtkControl = value;

           this.OnSetRenderControl();
           
           }
       }


       protected void OnSetRenderControl()
       {
           m_vtkRenderWindow = m_vtkControl.RenderWindow;
           this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().SetBackground(m_BackColor.R / 255.0f, m_BackColor.G / 255.0f, m_BackColor.B / 255.0f);


           //使用正交投影：平行映射；不使用透视投影：远处的小进处的大。
           this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().GetActiveCamera().ParallelProjectionOn();//开启平行／正交投影。此时需通过SetParallelScale()方法控制角色物体的缩放。Zoom不再有效。

           #region 尝试修改全局灯光设置


           //this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().LightFollowCameraOn();
           ////this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().LightFollowCameraOff ();
           //this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().RemoveAllLights();
           //this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().SetAutomaticLightCreation(0);
           ////this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().TwoSidedLightingOff();
           //this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().TwoSidedLightingOn ();
           //this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().AutomaticLightCreationOff();


           ////人眼看到物体是由于物体对光线的反射，如果物体不反射光，或着不向人的眼睛方向反射，人眼将认为这个物体是没有光照的,将使黑色的。
           ////绘制三维物体时将按照给定的顶点法向量值来计算这个面的明暗亮度
           //vtkLight light = vtkLight.New();
           ////light.SetFocalPoint(this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().GetActiveCamera().GetFocalPoint()[0], this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().GetActiveCamera().GetFocalPoint()[1], this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().GetActiveCamera().GetFocalPoint()[2]);
           ////light.SetPosition(this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().GetActiveCamera().GetPosition()[0], this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().GetActiveCamera().GetPosition()[1], this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().GetActiveCamera().GetPosition()[2]);

           ////light.SwitchOff();
           //light.SwitchOn();
           ////light.PositionalOn();//点光源？？
           ////light.SetConeAngle(180);

           ////注解
           ////Set/Get the type of the light. A SceneLight is a light located in the world coordinate space. 
           ////A light is initially created as a scene light. A Headlight is always located at the camera and
           //// is pointed at the camera's focal point. The renderer is free to modify the position and focal
           ////point of the camera at any time. A CameraLight is also attached to the camera, but is not necessarily
           ////located at the camera's position. CameraLights are defined in a coordinate space where the camera is
           ////located at (0, 0, 1), looking towards (0, 0, 0) at a distance of 1, with up being (0, 1, 0).
           ////Note: Use SetLightTypeToSceneLight, rather than SetLightType(3), since the former clears the light's transform matrix. 
           //light.SetLightTypeToCameraLight();
           ////light.SetLightTypeToHeadlight();
           //////light.SetLightTypeToSceneLight();
           ////light.SetIntensity(1);

           //light.SetColor(1, 1, 1);//白光


           //m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().AddLight(light);


           //m_vtkControl.RenderWindow.PolygonSmoothingOn();
           //m_vtkControl.RenderWindow.SetAlphaBitPlanes(1);
           //m_vtkControl.RenderWindow.SetMultiSamples(0);

           //m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().UseDepthPeelingOff();//关闭背面消隐   默认是off
           //m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().UseDepthPeelingOn();//无论绘制的先后，让距离远的物体总在距离近的物体后面。

           //m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().TwoSidedLightingOn();
           ////m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().SetLightFollowCamera(1);
    

           #endregion

           m_vtkRenderer = m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer();

           m_vtkInteractor = vtkRenderWindowInteractor.New();
           m_vtkRenderWindow.SetInteractor(m_vtkInteractor);



           //m_vtkInteractor.LightFollowCameraOff();
           //m_vtkInteractor.LightFollowCameraOn ();




           vtkInteractorStyle style = vtkInteractorStyleTrackballCamera.New();
           m_vtkRenderWindow.GetInteractor().SetInteractorStyle(style);

           //m_vtkInteractor.Initialize();
           //m_vtkInteractor.Start();



           //世界坐标系  辅助工具
           worldCoordinata = new WorldCoordinateWidget(m_vtkRenderWindow, m_vtkInteractor);
           worldCoordinata.InitialWorldCoordinateWidget();
    

           

       }
       #endregion



       #region 公共属性 包括：场景背景色，Node的颜色配置，等值线（面）的参数设置，Node的集合等。

       protected Color m_BackColor = Color.White;
       [Browsable(false)]
       public Color BackColor
       {
           get { return m_BackColor; }
           set
           {
               this.m_BackColor = value;
               this.OnSetBackColor();
           }
       }


       //。。。。。。。。。2011.7.20新添加属性。。。。。。。。
       //ContourSetup contourSetup;
       //public ContourSetup ContourSetup
       //{
       //    get { return contourSetup; }
       //    set { contourSetup = value; }
       //}
       //。。。。。。。。。。。。。。。。。。。。。。


       protected Dictionary<string, Node> nodeDic = new Dictionary<string, Node>();
       /// <summary>
       /// 存储节点，注意它的无序性
       /// </summary>
       public Dictionary<string, Node> NodeDic
       {
           get { return nodeDic; }     
       }


 

     

       //找清楚场景是否已经完全运行，甚至包括属性的前期定义，以及窗体是否已经准备完全。
       /// <summary>
       /// 默认false  ClearScene之后false；Render后true。
       /// </summary>
       bool _readyForUpdate = false;
  


       /// <summary>
       /// 表示数据层是否已经添加到控件中进行渲染
       /// 执行Render置为true；执行ClearScene置为false
       /// </summary>
       bool _isRendering;
       /// <summary>
       /// 表示数据层是否已经添加到控件中进行渲染
       /// 执行Render置为true；执行ClearScene置为false
       /// </summary>
       public bool IsRendering
       {
           get { return _isRendering; }
           set { _isRendering = value; }
       }

       #endregion



       #region 对外接口 包括：场景视角控制，场景的背景颜色控制，Node管理，Render，Update，Clear，保存文件等。

       public void OnSetBackColor()
       {
           //if (!this.IsRendering)
           //{
           //    return;
           //}

           this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().SetBackground(m_BackColor.R / 255.0f, m_BackColor.G / 255.0f, m_BackColor.B / 255.0f);
       }




       public void Render()
       {
           
           //this.m_vtkControl.RenderWindow.Render();


           this._isRendering = true;
           this._readyForUpdate = false;

           foreach (Node node in this.nodeDic.Values)
           {
               node.Render();
               
           }


           this._readyForUpdate = true;

           this.Update();

           //this.m_vtkControl.RenderWindow.Render();

           this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().ResetCamera();
       }

       /// <summary>
       /// 更新场景  RenderWindow  control的刷新显示
       /// </summary>
       public void Update()
       {
           if (_readyForUpdate)
           {
               this.m_vtkControl.RenderWindow.Render();//通知该RenderWindow的所有Renderer渲染自己所添加的Actor等。
               //this.m_vtkControl.Refresh();
           }
       }

       /// <summary>
       /// 添加一个Node   同时如果this._isRendering==true（执行过Scene的Render（）后则变为true） 则进行 Render（）操作。
       /// </summary>
       /// <param name="node"></param>
       public void AddNode(Node node)
       {

           node.Scene = this;
           this.nodeDic.Add(node.Name,node);

           if (this._isRendering )
           {
               node.Render();
               
           }
           
 
       }
       /// <summary>
       /// 删除一个Node 同时删除Actor和进行相应的资源的销毁
       /// </summary>
       /// <param name="id"></param>
       public void RemoveNode(string id)
       {


        

           if (this.nodeDic.ContainsKey(id))
           {
               if (this._isRendering)
               {
                   this.nodeDic[id].StopRender();

                  

               }

               this.nodeDic[id].Scene = null;
               this.nodeDic.Remove(id);
               
           }

           
       }
       /// <summary>
       /// 得到想要的Node
       /// </summary>
       /// <param name="id"></param>
       /// <returns></returns>
       public Node GetNode(string id)
       {
           if (this.nodeDic.ContainsKey(id))
           {


               return this.nodeDic[id];


           }
           else
           {
               return null;
           }
 
       }

       /// <summary>
       /// 清除场景
       /// </summary>
       public void ClearScene()
       {
           foreach (KeyValuePair<string, Node> item in nodeDic)
           {
               item.Value.StopRender();
              
           }


           nodeDic.Clear();

           this.Update();



           //这里这样写给其它的场景会带来麻烦，但是目前只能这样了
          this.IsRendering = false;

           //第二次加载无忧

           _readyForUpdate = false;

           System.GC.Collect();
       }



       
       /// <summary>
       /// 视角控制API
       /// 调用该方法要注意 不要和Update（）等方法同时调用，因为都包括  RenderWindow.Render()，导致多次渲染很容易出错和降低效率
       /// </summary>
       public void ResetView()
       {

           this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().ResetCamera();

           //this.m_vtkControl.RenderWindow.Render();//通知渲染刷新显示
       }


       /// <summary>
       /// 设置不同的视图模式，函数有待进一步验证
       /// </summary>
       /// <param name="type"></param>
       public void SetView(VIEWTYPE type)
       {

           vtkCamera camera = this.m_vtkControl.RenderWindow.GetRenderers().GetFirstRenderer().GetActiveCamera();

           switch (type)
           {
               case VIEWTYPE.TOP:
                   //Z+ 方向  平面横向向右X+  纵向向上为Y+
                   camera.SetFocalPoint(0,0,0);
                   camera.SetViewUp(0,1,0);
                   camera.SetPosition(0,0,1);

                 

                   break;
               case VIEWTYPE.FRONT:
                   //Y+ 方向  平面横向向右X+  纵向向上为Z+
                   camera.SetFocalPoint(0, 0, 0);
                    camera.SetViewUp(0,0,1);
                    camera.SetPosition(0,-1,0);

                  
                   break;
               case VIEWTYPE.LEFT:
                   //X- 方向  平面横向向右Z+  纵向向上为Y+
                   //camera.SetFocalPoint(0, 0, 0);
                   // camera.SetViewUp(0,1,0);
                   // camera.SetPosition(-1, 0, 0);

                   

                   break;
               case VIEWTYPE.BOTTOM:
                   //Z- 方向  平面横向向左X+  纵向向上为Y+
                   //camera.SetFocalPoint(0, 0, 0);
                   // camera.SetViewUp(0,1,0);
                   // camera.SetPosition(0, 0, -1);
                  
                   break;
               case VIEWTYPE.RIGHT:
                   //X+ 方向  平面横向向右Y+  纵向向上为Z+
                   camera.SetFocalPoint(0, 0, 0);
                    camera.SetViewUp(0,0,1);
                    camera.SetPosition(1, 0, 0);
                   
                   break;
               case VIEWTYPE.BACK:
                   //Y- 方向  平面横向向右X+  纵向向上为Z+
                   //camera.SetFocalPoint(0, 0, 0);
                   //camera.SetViewUp(0, 0, 1);

                   //camera.SetPosition(0, -1, 0);

                   break;
               case VIEWTYPE.PERSPECTIVE:


                   break;
               default:
                   break;
           }


           camera.ComputeViewPlaneNormal();

           this.ResetView();
           
 
       }


       //序列化设置



       /// <summary>
       /// 加载项目场景文件
       /// </summary>
       /// <param name="fname"></param>
       /// <returns></returns>


       public bool LoadSceneBinary(string fname)
       {

           //在加载之前，首先进行清空的逻辑

           this.ClearScene();




           BinaryFormatter bf = new BinaryFormatter();

           //将文件属性设为普通，哈哈

           Stream stream = new FileStream(fname, FileMode.Open, FileAccess.Read, FileShare.None);


           try
           {

               nodeDic = (Dictionary<string, Node>)bf.Deserialize(stream);


               stream.Close();

           }
           catch (Exception ex)
           {
               //MessageBox.Show("错误：" + ex.Message);
               Console.WriteLine("错误：" + ex.Message);
               return false;

           }





           foreach (KeyValuePair<string, Node> item in nodeDic)
           {
               item.Value.ReLoad();

               //if (NodeAdded != null)
               //{
               //    NodeAdded(item.Value);
               //}

           }

           //this.Run();

           //FuEngine.GetEngine().IsRunning = true;

           //this.InitProp();



           return true;

       }
       public bool SaveSceneBinary(string fname)
       {

           BinaryFormatter bf = new BinaryFormatter();

           Stream stream = new FileStream(fname, FileMode.Create, FileAccess.Write);


           try
           {

               bf.Serialize(stream, nodeDic);

               stream.Close();

           }
           catch (Exception ex)
           {
               //MessageBox.Show("错误：" + ex.Message);

               Console.WriteLine("错误：" + ex.Message);
               return false;

           }


           return true;

       }




       public void SaveScreenShot(SaveScreenSetup setup)
       {


           ////伪代码  测试

           //SaveScreenType imageType = SaveScreenType.BMP;
           //string imageSavePath = "C:\\Documents and Settings\\Administrator\\桌面\\新建文件夹 (2)\\testImage.bmp";
           //System.Windows.Forms.SaveFileDialog saveFile = new System.Windows.Forms.SaveFileDialog();
           //saveFile.Filter = "pnm files(*.pnm)|*.pnm|  png files(*.png)|*.png| bmp files(*.bmp)|*.bmp|jpeg files(*.jpeg)|*.jpeg|All files(*.*)|*.*";
           //saveFile.FilterIndex = 1;
           //saveFile.RestoreDirectory = true;
           //if (saveFile.ShowDialog() == System.Windows.Forms.DialogResult.OK)
           //{
           //    imageSavePath = saveFile.FileName;

           //    if (System.IO.File.Exists(imageSavePath))
           //    {
           //        System.IO.File.Delete(imageSavePath);
           //    }

           //    SaveScreenSetup setup = new SaveScreenSetup(imageType, imageSavePath);

           //    if (this._vtkScene != null)
           //    {
           //        this._vtkScene.SaveScreenShot(setup);
           //    }
           //}






           if (setup == null)
           {
               return;
           }

           //if (File.Exists(setup.ImageSavePath))
           //{
           //    return;
           //}

           try
           {
               if (this.m_vtkRenderer == null)
               {
                   return;
               }


               //vtkRenderWindow renderWin = this.m_vtkRenderWindow;
               //vtkRenderer renderer = renderWin.GetRenderers().GetFirstRenderer();
               ////renderWin.OffScreenRenderingOn();
               //vtkRenderLargeImage largeImage = vtkRenderLargeImage.New();
               //largeImage.SetInput(renderer);
               //largeImage.SetMagnification(1);


        


               if (this.m_vtkRenderWindow == null)
               {
                   return;
               }


               vtkWindowToImageFilter imageFilter = vtkWindowToImageFilter.New();

               imageFilter.SetInput(this.m_vtkRenderWindow);

               if (setup .Resolution <1)
               {
                   setup.Resolution = 1;
               }

               imageFilter.SetMagnification(setup.Resolution );


               //imageFilter.SetMagnification(1);


               imageFilter.Update();

               //imageFilter.SetInputBufferTypeToRGBA();//also record the alpha (transparency) channel
               ////imageFilter.SetInputBufferTypeToRGBA();//also record the alpha (transparency) channel
               ////imageFilter.SetInputBufferTypeToRGBA();//also record the alpha (transparency) channel
               //imageFilter.SetInputBufferTypeToRGB ();



               switch (setup.ImageType)
               {
                   case SaveScreenType.JEPG:



                       //System .Drawing .Bitmap bitmap= imageFilter.GetOutput().ToBitmap();



                       vtkJPEGWriter jpegWriter = vtkJPEGWriter.New();

                       jpegWriter.SetInput(imageFilter.GetOutput());

                       jpegWriter.SetFileName(setup.ImageSavePath);//保存的完整路径

                       //jpegWriter.SetFileDimensionality(3);
                       jpegWriter.SetFileDimensionality(2);
 

                       jpegWriter.Write();


                       jpegWriter.Dispose();
                       jpegWriter = null;


                       break;
                   case SaveScreenType.BMP:

                       
                       vtkBMPWriter bmpWriter = vtkBMPWriter.New();

                       bmpWriter.SetInput(imageFilter.GetOutput());

                       //bmpWriter.SetInput(largeImage.GetOutput ());

                       bmpWriter.SetFileName(setup.ImageSavePath);//保存的完整路径

                       //bmpWriter.SetFilePattern("bmp");
                       //bmpWriter.SetFileDimensionality(3);
                       bmpWriter.SetFileDimensionality(2);

                       //largeImage.Modified();


                       bmpWriter.Write();

                       bmpWriter.Update();

                       //renderWin = null;
                       //renderWin.OffScreenRenderingOff ();


                       bmpWriter.Dispose();
                       bmpWriter = null;


                       break;
                   case SaveScreenType.PNM:

                       vtkPNMWriter pnmWriter = vtkPNMWriter.New();
                       pnmWriter.SetInput(imageFilter.GetOutput());

                       pnmWriter.SetFileName(setup.ImageSavePath);//保存的完整路径

                       //pnmWriter.SetFileDimensionality(3);
                       pnmWriter.SetFileDimensionality(2);

                       pnmWriter.Write();

                       pnmWriter.Dispose();
                       pnmWriter = null;


                       break;
                   case SaveScreenType.PNG:

                       vtkPNGWriter pngWriter = vtkPNGWriter.New();

                       pngWriter.SetInput(imageFilter.GetOutput());


                       pngWriter.SetFileName(setup.ImageSavePath);//保存的完整路径

                       //pngWriter.SetFileDimensionality(3);
                       pngWriter.SetFileDimensionality(2);
                       pngWriter.Write();

                       pngWriter.Dispose();
                       pngWriter = null;


                       break;
                   default:
                       break;
               }



               imageFilter.Dispose();
               imageFilter = null;


           }
           catch
           {

               System.Windows.Forms.MessageBox.Show("保存图片过程出错！");

               return;

           }
       }




       public System.Drawing.Bitmap GetvtkImage(int resolution)
       {

           if (resolution <1)
           {
               resolution = 1;

           }


           if (this.m_vtkRenderer == null)
           {
               return null;
           }



           if (this.m_vtkRenderWindow == null)
           {
               return null;
           }


           vtkWindowToImageFilter imageFilter = vtkWindowToImageFilter.New();

           imageFilter.SetInput(this.m_vtkRenderWindow);

           

           imageFilter.SetMagnification(resolution);

           imageFilter.Update();

           return imageFilter.GetOutput().ToBitmap();
       
       }



       #endregion



   }
}
